#ifndef _TEXTURE_H
#define _TEXTURE_H

#if C2504
#pragma message("Texture.h")
#endif

#include "Scene.h"

class TextureMgr;
class Scene;

//==========================================================================
//			Texture or Surface
//==========================================================================
/*
Texture		texture for rendering. Can have mipmaps and can be compressed 
			(depends on file format). Not GDI-compatible can't be used in
			D3D11Pad or Blit/Fill functions. Gets immediately converted if 
			such requst has been made.

Surface		texture for GDI, D3D11Pad and Blit/Fill usage. Can't have  mipmaps
			Can't be compressed. Can only have B8G8R8A8 format.
*/
class Texture {
	friend class Overlay;
	friend class TextureMgr;
public:	
	Texture( TextureMgr * textureMgr, DWORD w, DWORD h );
	Texture( TextureMgr * textureMgr, DWORD w, DWORD h, void *data );
	Texture( TextureMgr * textureMgr, DWORD w, DWORD h, DXGI_FORMAT Format, const char *fname, bool alpha );
	Texture( TextureMgr * textureMgr, const char *fname, const char *nameWithPath = nullptr );
	~Texture();

	bool HasAlpha()	{ return has_alpha; }
	bool IsTex()	{ return bTex;	}
	void GetSize( DWORD *w, DWORD *h );
	void SetColorKey( DWORD ckey );
	char *GetFileName()	{	return file_name;	}
	HDC GetDC();
	void ReleaseDC();

	ID3D11Texture2D *GetTex()			{	return Tex;		}
	IDXGISurface1 *GetSurf()			{	return Surf;	}
	ID3D11ShaderResourceView **GetSRV()	{	return bSRV ? &SRV : CreateSRV();	}
	ID3D11RenderTargetView **GetRTV()	{	return bRTV ? &RTV : CreateRTV();	}
	bool IsGDIUsed() const { return m_gdiUsed; }
private:
	TextureMgr * m_textureMgr;
	bool FindAlpha( DXGI_FORMAT format );
	ID3D11ShaderResourceView **CreateSRV();
	ID3D11RenderTargetView **CreateRTV();

	CComPtrEx<IDXGISurface1> Surf;	//used only for surfaces
	CComPtrEx<ID3D11Texture2D> Tex;
	CComPtrEx<ID3D11Texture2D> m_gdiTex;
	CComPtrEx<ID3D11ShaderResourceView> m_gdiTexSRV;
	CComPtrEx<ID3D11RenderTargetView> m_gdiTexRTV;

	bool CreateGDIShadowSurface();

	UINT RefCounter;
	DWORD
		width,
		height;
	D3DXCOLOR ColorKey;
	bool
		bTex,		//is texture
		bColorKey,	//has assigned color key
		bSRV,	//SRV was created
		bRTV;	//RTV was created
	bool m_gdiUsed;
	CComPtrEx<ID3D11ShaderResourceView> SRV;
	CComPtrEx<ID3D11RenderTargetView> RTV;

	char *file_name;
	bool has_alpha;
};

//==========================================================================
//			Texture Manager does modifications of textures/surfaces
//==========================================================================
//Blit/Fill buffer
//

//Texture before deletion
//
struct TempTexture {
	Texture *tex;
	UINT counter;
};
//Command.	(Used for writing Blit/Fill calls to command buffer while in 2-threaded mode )
//
typedef struct Data {
	Texture
		*tgt,
		*src;
	DWORD
		tgtx,
		tgty,
		tgtw,
		tgth,
		srcx,
		srcy,
		srcw,
		srch,
		flags;
} Data;

struct Command {
	DWORD type;
	Data params;
};

//TextureMgr class
//
class TextureMgr {
	friend class D3D11Client;
public:
	TextureMgr();
	~TextureMgr();
//create/delete
	Texture *CreateSurfaceBitmap( HBITMAP hbm );
	Texture *CreateSurface( DWORD w, DWORD h );
	Texture *CreateSurfaceEx( DWORD w, DWORD h, DWORD attrib );

	void Execute2DOperation(ID3D11ShaderResourceView ** srv, ID3D11RenderTargetView ** rtv, UINT width, UINT height, UINT operationCode);

	Texture *LoadTextureFromFile( const char *fname, DWORD flags );
	Texture *LoadNormalMapFromFile( const char *nname );
	Texture *LoadBumpMapFromFile( const char *bname );
	Texture *LoadSpecularMapFromFile( const char *sname );
	Texture *LoadEmissiveMapFromFile( const char *ename );

	void ReleaseTexture( Texture *tex );
//-------------------------------
	bool CopyBitmap( Texture *tex, HBITMAP hbm, int x, int y, int dx, int dy );
	HDC GetSurfaceDC( Texture *tex );
	void ReleaseSurfaceDC( HDC hdc, Texture *tex );
	bool FillSurface( Texture *tex, DWORD col );
	bool FillSurfaceRect( Texture *tex, DWORD tgtx, DWORD tgty, DWORD w, DWORD h, DWORD col );
	bool Blit1( Texture *tgt, DWORD tgtx, DWORD tgty, Texture *src, DWORD flags );
	bool Blit2( Texture *tgt, DWORD tgtx, DWORD tgty, Texture *src, DWORD srcx, DWORD srcy, DWORD w, DWORD h, DWORD flags );
	bool ScaleBlit( Texture *tgt, DWORD tgtx, DWORD tgty, DWORD tgtw, DWORD tgth, Texture *src, DWORD srcx, DWORD srcy, DWORD srcw, DWORD srch, DWORD flags );
//-------------------------------
	void GetSize( Texture *tex, DWORD *w, DWORD *h );
	DWORD GetDevColor( BYTE r, BYTE g, BYTE b );
	void IncrSurfaceRef( Texture *tex );
	bool SetColorKey( Texture *tex, DWORD ckey );
	
	void GInit();
//texture "catalog"
//	
	void AddTexture( Texture *tex );	//adds a texture into a texture catalog
	bool Find( Texture *tex );			//finds a texture if it exists
	bool DeleteTexture( Texture *tex );	//deletes a texture if it exists
	void ClearRemainingTextures();		//clears all textures
	Texture **List;
	DWORD
		ListMax,
		Free;
//--------------------------------
//		global textures
//--------------------------------
	void AddGlobalTexture( Texture *tex );
	Texture *SearchGlobalTexture( const char *fname );
	bool FindGlobal( Texture *tex );
	void DeleteGlobalTextures();
	Texture **GList;
	DWORD
		GListMax,	//
		GFree;		//first free element

//--------------------------------
//		?
//--------------------------------
	void AddToQueue( Texture *tex );
	void FrameRendered();
	void ClearQueue();
	TempTexture Queue[1024];
	UINT InQueue;
//--------------------------------
//		texture buffer
//--------------------------------
	void InitBuffer();
	Texture *FindBuffer( DWORD w, DWORD h );
	void ClearBuffer();

	struct BufferTexture {
		Texture *tex;
		DWORD dim;
	} *Buffer;

	UINT BufferCount;
//executes all commands in the command list
//
	void ExecuteCommandList();

	void ConvertTextureToSurface( Texture *tex );
private:
	Texture *CreateTextureFromBitmap( HBITMAP hbm );
	Texture *CreateTextureFromBitmapRect( HBITMAP hbm, int x, int y, int dx, int dy );
	void RenderRect( Texture *tex, float tgtx, float tgty, float w, float h, DWORD col );
	void Render( Texture *tgt, float tgtx, float tgty, float tgtw, float tgth, Texture *src, float srcx, float srcy, float w, float h, DWORD flags );

	void AddToCommandList( DWORD type, Data *data );	//adds a command
	
	void _CopyBitmap( Data *prm );
	void _FillSurface1( Data *prm );
	void _FillSurface2( Data *prm );
	void _Blit1( Data *prm );
	void _Blit2( Data *prm );
	void _ScaleBlit( Data *prm );
	void _ConvertToSurface( Data *prm );

//command list
//
	DWORD CommandCount, CommandMax;
	Command *CList;

//effect
//
	ID3D11InputLayout *IL_Blit;
	ID3D11VertexShader *VS_Blit;
	ID3D11PixelShader *PS_Blit;
	ID3D11Buffer
		*VB,
		*IB,
		*cb_VS,
		*cb_PS;

	D3DXMATRIX Orth;
	UINT dcCounter, BBufDC;	

	void Init2DRendering();
	
	CComPtrEx<ID3D11Buffer> m_2dData;
	CComPtrEx<ID3D11Buffer> m_2dDataSettingsBuffer;
	CComPtrEx<ID3D11InputLayout> m_2dBufferLayout;
	CComPtrEx<ID3D11VertexShader> m_2dBufferVS;
	CComPtrEx<ID3D11PixelShader> m_2dBufferPS;
};

#endif